ECMAScript 2023(简称 ES 14)于 2023 年 6 月正式发布。它在现有特性基础上增加了几个实用功能,主要聚焦于数组操作的便捷性、不可变数据处理 和 WeakMap 功能扩展,进一步诶生了代码的可读性和开发效率。
一、 数组的 4 个不可变操作方法
1. toReversed() 反转数组(不可变版的 reverse())
toReversed() 返回一个元素顺序相反的新数组,而不影响原数组。
const arr = [1, 2, 3, 4];
const reversed = arr.toReversed();
console.log(reversed); // [4, 3, 2, 1]
console.log(arr); // [1, 2, 3, 4](原数组未变)
2. toSorted(compareFn) 排序数组(不可变版的 sort())
toSorted() 返回一个按指定规则排序的新数组,原数组不变。
const arr = [2, 1, 3, 5, 4, 6];
const sorted = arr.toSorted((a, b) => a - b);
// [1, 2, 3, 4, 5, 6]
console.log(sorted);
// [2, 1, 3, 5, 4, 6]
console.log(arr);
3. toSpliced(start, deleteCount, ...items) 数据切片
toSpliced(start, deleteCount, ...items) 返回一个删除/插入元素后的新数组,原数组不变。是一个不可变版本的 splice()。
const arr = [1, 2, 3, 4];
const spliced = arr.toSpliced(1, 2, 5, 6);
// [1, 5, 6, 4]
console.log(spliced);
// [1, 2, 3, 4]
console.log(arr);
4. with(index, value) 修改指定索引的元素
with(index, value) 返回一个指定索引元素被更新的新数组,原数组不变。替代了直接修改数组元素的操作,避免了副作用。
const arr = [1, 2, 3];
const updated = arr.with(1, 10);
// [1, 10, 3];
console.log(updated);
// [1, 2, 3];
console.log(arr);
二、 从数组尾部开始查找元素: findLast() 和 findLastIndex()
1. findLast(callback, thisArg)
从数组的最后一个元素开始遍历,返回第一个满足回调函数条件的元素。
const numbers = [1, 3, 5, 7, 8];
// 查找最后一个偶数
const lastEven = numbers.findLast(e => 0 === e % 2);
console.log(lastEven); // 8
2. findLastIndex(callback, thisArg)
从数组最后一个元素开始遍历,返回第一个满足条环的元素的索引。
const arr = [1, 3, 5, 7, 8];
// 查找最后一个偶数的索引
const lastEvenIndex = arr.findLastIndex(e => 0 === e % 2);
console.log(lastEvenIndex); // 4
三、 WeakMap 支持不可扩展对象作为键
在 ES2023 之前,WeakMap 的键只能是 「可扩展对象」(即未被 Object.freeze()、Object.seal() 处理的对象),否则会抛出 TypeError。在 ES2023 放宽了这一限制,允许不可扩展对象作为 WeakMap 的键,扩展了 WeakMap 的使用场景。
const wm = new WeakMap();
/** 不可扩展对象 */
const frozenObj = Object.freeze({ id: 1 });
// ES2023 之前回报错,现在允许
wm.set(frozenObj, 'frozen value');
// 'frozen value'
console.log(wm.get(frozenObj));
四、 Hashbang 语法标准化
ES2023 正式将 Hashbang (也称为 shebang)语法纳入标准。Hashbang 是 Unix/Linux 系统中用于指定脚本解释器的特殊注释语法。如:#!/usr/bin/env node。
这一特性的引入使得 JavaScript 脚本可以在 Unix-like 系统上执行,提高了脚本的可移植性和执行效率。同时,Hashbang 语法也支持在模块目标中使用,进一步扩展了其应用场景。
五、 Object.groupBy()
将数组按指定的规则分组,返回一个对象(键是分组的依据,值作为该组的元素数组)。这个方法提供了原生的数据分组解决方案,简化了传统的 reduce 方法进行分组的复杂操作。
/** 库存 */
const inventory = [
{ name: '莴笋', type: '蔬菜', quantity: 9 },
{ name: '香蕉', type: '水果', quantity: 5 },
{ name: '肉鸡', type: '肉', quantity: 23 },
{ name: '樱桃', type: '水果', quantity: 12 },
{ name: '鲅鱼', type: '肉', quantity: 22 },
{ name: '肉鸡', type: '肉', quantity: 23 },
];
/** 补货 */
const restock = { restock: true };
/** 量足 */
const sufficient = { restock: false };
const result = Object.groupBy(inventory, ({ quantity }) =>
quantity < 6 ? 'restock' : 'sufficient',
);
// 打印需要补货的
// [{name: '香蕉' , type: '水果', quantity: 5}]
console.log(result.restock);
/** 如果按照类型分类 */
const resultType = Object.groupBy(inventory, ({ type }) => type);
/**
* {
* 蔬菜: [
* { name: '莴笋', type: '蔬菜', quantity: 9 },
* ],
* 水果: [
* { name: '香蕉', type: '水果', quantity: 5 },
* { name: '樱桃', type: '水果', quantity: 12 },
* ],
* 肉: [
* { name: '鲅鱼', type: '肉', quantity: 22 },
* { name: '肉鸡', type: '肉', quantity: 23 },
* ],
* }
*
*/
console.log(resultType);
六、 装饰器
通过 @ 语法修改类或类方法的行为,实现横切关注点(如日志、缓存、权限校验)的复用。装饰器是元编程的终极武器,可以提高代码的可维护性和可扩展性。